﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;

namespace Expect.Report.Word
{
    class TOCHelpers
    {
        /*
        /// <summary>
        /// returns title paragraphs of genereated doc fro creating toc hyperlink
        /// </summary>
        private IEnumerable<XElement> TitleParagraphsElements(XDocument mainDocument)
        {

            IEnumerable<XElement> results =
              mainDocument.Descendants().Where
              (
                  tag =>
                      tag.Name == ns + "p" &&
                      tag.Descendants(ns + "t").Count() > 0 &&
                      tag.Descendants().Where
                      (
                        tag2 =>
                            tag2.Name == ns + "pStyle" &&
                            (
                                tag2.Attribute(ns + "val").Value == "Heading1" ||
                                tag2.Attribute(ns + "val").Value == "Heading2" ||
                                tag2.Attribute(ns + "val").Value == "Heading3" ||
                                tag2.Attribute(ns + "val").Value == "Heading4" ||
                                tag2.Attribute(ns + "val").Value == "Heading5" ||
                                tag2.Attribute(ns + "val").Value == "Heading6"
                            )
                      ).Count() > 0
              );

            return results;
        }

        /// <summary>
        /// Generate the Table Of Contents(TOC) of the document
        /// </summary>
        private void GenerateTOC(XDocument xmlMainDocument, XElement TOCRefNode)
        {
            int bookMarkIdCounter = 0;
            int maxHeading = 1;
            int tempheading = 1;

            //  sdtContent, will contain all the paragraphs used in the TOC
            XElement sdtContent = new XElement(ns + "sdtContent");
            String strContentHdr = "";
            XElement xContentHdr = TOCRefNode.Elements(ns + "sdtContent").First().Descendants().Where(
                tag =>
                    tag.Name == ns + "p" &&
                    tag.Descendants().Where
                    (
                        tag2 =>
                            tag2.Name == ns + "pStyle" &&
                            tag2.Attribute(ns + "val").Value == "TOCHeading"
                    ).Count() > 0
                ).FirstOrDefault();

            if (xContentHdr != null)
                strContentHdr = xContentHdr.Descendants(ns + "t").FirstOrDefault().Value;

            //  build the title of the TOC and add it in the sdtContent element, and
            //  some information regarding the attributes of the TOC
            xContentHdr.Add(

                        new XElement(ns + "r",
                            new XElement(ns + "fldChar",
                                    new XAttribute(ns + "fldCharType", "begin"))),
                        new XElement(ns + "r",
                            new XElement(ns + "instrText",
                                new XAttribute(XNamespace.Xml + "space", "preserve"),
                                "TOCLIMIT")),
                        new XElement(ns + "r",
                            new XElement(ns + "fldChar",
                                new XAttribute(ns + "fldCharType", "separate"))));
            sdtContent.Add(new XElement(xContentHdr));



            //  for each title found it in the document, we have to wrap the run inside of it,
            //  with a bookmark, this bookmark will have an id which will work as an anchor,
            //  for link references in the TOC
            foreach (XElement titleParagraph in TitleParagraphsElements(xmlMainDocument))
            {
                string bookmarkName = bookmarkNamePrefix + bookMarkIdCounter;
                XElement bookmarkStart =
                    new XElement(ns + "bookmarkStart",
                        new XAttribute(ns + "id", bookMarkIdCounter),
                        new XAttribute(ns + "name", bookmarkName));
                XElement bookmarkEnd =
                    new XElement(ns + "bookmarkEnd",
                        new XAttribute(ns + "id", bookMarkIdCounter));

                //  wrap the run with bookmarkStart and bookmarkEnd
                titleParagraph.AddFirst(bookmarkStart);
                titleParagraph.Add(bookmarkEnd);

                //  get the name of the style of the parapgraph of the title, and for each one,
                //  choose a style to add in the paragraph inside the TOC
                string referenceTitleStyle = "";
                switch (titleParagraph.Descendants(ns + "pStyle").First().Attribute(ns + "val").Value)
                {
                    case "Heading1":
                        {
                            referenceTitleStyle = "TOC1";
                            tempheading = 1;
                            break;
                        }
                    case "Heading2":
                        {
                            referenceTitleStyle = "TOC2";
                            tempheading = 2;
                            break;
                        }
                    case "Heading3":
                        {
                            referenceTitleStyle = "TOC3";
                            tempheading = 3;
                            break;
                        }
                    case "Heading4":
                        {
                            referenceTitleStyle = "TOC4";
                            tempheading = 4;
                            break;
                        }
                    case "Heading5":
                        {
                            referenceTitleStyle = "TOC5";
                            tempheading = 5;
                            break;
                        }
                    case "Heading6":
                        {
                            referenceTitleStyle = "TOC6";
                            tempheading = 6;
                            break;
                        }
                }


                string entryContent = "";
                IEnumerable<XElement> owTList = titleParagraph.Descendants(ns + "t");
                foreach (XElement entryElement in owTList)
                {
                    entryContent += (entryElement == null ? string.Empty : entryElement.Value);
                }

                XElement TOCElement = null;
                XElement tempTOCElement = TOCRefNode.Elements(ns + "sdtContent").First().Descendants().Where(
                tag =>
                    tag.Name == ns + "p" &&
                    tag.Descendants().Where
                    (
                        tag2 =>
                            tag2.Name == ns + "pStyle" &&
                            tag2.Attribute(ns + "val").Value == referenceTitleStyle
                    ).Count() > 0
                ).FirstOrDefault();

                if (tempTOCElement != null)
                {
                    if (maxHeading < tempheading)
                        maxHeading = tempheading;

                    TOCElement = new XElement(tempTOCElement);
                    //delete instrText which contains TOC 1-n
                    XElement instrTextTOC = TOCElement.Descendants().Where(
                            tag =>
                                tag.Name == ns + "r" &&
                                tag.Descendants().Where(
                                    tag2 =>
                                        tag2.Name == ns + "instrText" &&
                                        tag2.Value.Contains(@"TOC \o ")
                                ).Count() > 0

                        ).FirstOrDefault();
                    if (instrTextTOC != null)
                    {
                        instrTextTOC.ElementsAfterSelf(ns + "r").Remove();
                        instrTextTOC.ElementsBeforeSelf(ns + "r").Remove();
                        instrTextTOC.Remove();
                    }

                    //get hyperlink node
                    XElement hyperlink = TOCElement.Descendants().Where(
                            tag =>
                                tag.Name == ns + "hyperlink"

                        ).FirstOrDefault();
                    //update anchor attribute value
                    hyperlink.Attribute(ns + "anchor").Value = bookmarkName;

                    //get entry content node
                    XElement contentNode = hyperlink.Descendants().Where(
                            tag =>
                                tag.Name == ns + "r" &&
                                tag.Descendants().Where(
                                    tag2 =>
                                        tag2.Name == ns + "rStyle" &&
                                        tag2.Attribute(ns + "val").Value == "Hyperlink"
                                ).Count() > 0 &&
                                tag.Elements(ns + "t").Count() > 0

                        ).FirstOrDefault().Elements(ns + "t").FirstOrDefault();

                    contentNode.Value = entryContent;

                    //update PAGEREF value
                    XElement instrText = TOCElement.Descendants().Where(
                            tag =>
                                tag.Name == ns + "instrText" &&
                                tag.Value.Contains("PAGEREF ")
                        ).FirstOrDefault();
                    if (instrText != null)
                    {
                        instrText.Value = " PAGEREF " + bookmarkName + @" \h ";
                    }

                    sdtContent.Add(TOCElement);
                    bookMarkIdCounter++;
                }


            }

            sdtContent.Descendants().Where(
                tag =>
                    tag.Name == ns + "instrText" &&
                    tag.Value.Contains("TOCLIMIT")
                ).FirstOrDefault().Value = String.Format(@" TOC \o ""1-{0}"" \h \z \u ", maxHeading);

            sdtContent.Add(
                new XElement(ns + "p",
                    new XElement(ns + "r",
                        new XElement(ns + "fldChar",
                            new XAttribute(ns + "fldCharType", "end")))));

            //  Finish the xml construction of the TOC
            XElement TOC =
                new XElement(ns + "sdt",
                    new XElement(ns + "sdtPr",
                        new XElement(ns + "docPartObj",
                            new XElement(ns + "docPartGallery",
                                new XAttribute(ns + "val", "Table of Contents")),
                            new XElement(ns + "docPartUnique"))),
                    sdtContent);

            //  add it to the original document

            IEnumerable<XElement> tocNodes = xmlMainDocument.Descendants().Where
              (
                  tag =>
                      tag.Name == ns + "sdt" &&
                      tag.Descendants(ns + "sdtContent").Count() > 0 &&
                      tag.Descendants().Where
                      (
                        tag2 =>
                            tag2.Name == ns + "p" &&
                            tag2.Descendants().Where
                            (
                                tag3 =>
                                    tag3.Name == ns + "pStyle" &&
                                        (
                                            tag3.Attribute(ns + "val").Value == "TOCHeading"
                                        )
                            ).Count() > 0

                      ).Count() > 0
              );


            TOCRefNode.ReplaceWith(TOC);

        }
*/

        /*
         using (WordprocessingDocument WorDocument = WordprocessingDocument.Create(@"C:\TestDocuments\Business Case Document.docx", WordprocessingDocumentType.Document))
            {
                // Add a new main document part. 
                MainDocumentPart mainPart = WorDocument.AddMainDocumentPart();
                //Create Document tree for simple document. 
                mainPart.Document = new Document();
                //Create Body (this element contains other elements that we want to include 
                Body body = new Body();
                

                //Save changes to the main document part. 
                mainPart.Document.Append(body);
                
                XDocument xmlXdocument = XDocument.Parse(mainPart.Document.InnerXml);
                IEnumerable<XElement> xmlelement = xmlXdocument.Descendants(ns + "sdt");
                XElement TOCRefNode = xmlelement.First();
                GenerateTOC(xmlXdocument, TOCRefNode);

                mainPart.Document.InnerXml = xmlXdocument.ToString();
                
                mainPart.Document.Save();
                WorDocument.Close();

            }

  #region TOC Creation
            /// <summary>
            /// returns title paragraphs of genereated doc fro creating toc hyperlink
            /// </summary>
        private static IEnumerable<XElement> TitleParagraphsElements(XDocument mainDocument)
        {
            IEnumerable<XElement> results = mainDocument.Descendants().Where
              (
                  tag =>
                      tag.Name == ns + "p" &&
                      tag.Descendants(ns + "t").Count() > 0 &&
                      tag.Descendants().Where
                      (
                        tag2 =>
                            tag2.Name == ns + "pStyle" &&
                            (
                                tag2.Attribute(ns + "val").Value == "Head1" ||
                                tag2.Attribute(ns + "val").Value == "Head2" ||
                                tag2.Attribute(ns + "val").Value == "Head3" ||
                                tag2.Attribute(ns + "val").Value == "Head4" ||
                                tag2.Attribute(ns + "val").Value == "Head5" ||
                                tag2.Attribute(ns + "val").Value == "Head6" 
                            )
                      ).Count() > 0
              );

            return results;
        }

        private static  void GenerateTOC(XDocument xmlMainDocument, XElement TOCRefNode)
        {
            int bookMarkIdCounter = 0;
            int maxHeading = 1;
            int tempheading = 1;

            //  sdtContent, will contain all the paragraphs used in the TOC
            XElement sdtContent = new XElement(ns + "sdtContent");
            String strContentHdr = "";
            XElement xContentHdr = TOCRefNode.Elements(ns + "sdtContent").First().Descendants().Where(
                tag =>
                    tag.Name == ns + "p" &&
                    tag.Descendants().Where
                    (
                        tag2 =>
                            tag2.Name == ns + "pStyle" &&
                            tag2.Attribute(ns + "val").Value == "TOCHeading"
                    ).Count() > 0
                ).FirstOrDefault();

            if (xContentHdr != null)
                strContentHdr = xContentHdr.Descendants(ns + "t").FirstOrDefault().Value;

            //  some information regarding the attributes of the TOC
            xContentHdr.Add(

                        new XElement(ns + "r",
                            new XElement(ns + "fldChar",
                                    new XAttribute(ns + "fldCharType", "begin"))),
                        new XElement(ns + "r",
                            new XElement(ns + "instrText",
                                new XAttribute(XNamespace.Xml + "space", "preserve"),
                                "TOCLIMIT")),
                        new XElement(ns + "r",
                            new XElement(ns + "fldChar",
                                new XAttribute(ns + "fldCharType", "separate"))));
            sdtContent.Add(new XElement(xContentHdr));


            //  for each title found it in the document, we have to wrap the run inside of it,
            //  with a bookmark, this bookmark will have an id which will work as an anchor,
            //  for link references in the TOC
            foreach (XElement titleParagraph in TitleParagraphsElements(xmlMainDocument))
            {
                string bookmarkName = "_TOC" + bookMarkIdCounter;
                XElement bookmarkStart =
                    new XElement(ns + "bookmarkStart",
                        new XAttribute(ns + "id", bookMarkIdCounter),
                        new XAttribute(ns + "name", bookmarkName));
                XElement bookmarkEnd =
                    new XElement(ns + "bookmarkEnd",
                        new XAttribute(ns + "id", bookMarkIdCounter));

                //  wrap the run with bookmarkStart and bookmarkEnd
                titleParagraph.AddFirst(bookmarkStart);
                titleParagraph.Add(bookmarkEnd);

                //  get the name of the style of the parapgraph of the title, and for each one,
                //  choose a style to add in the paragraph inside the TOC
                string referenceTitleStyle = "";
                switch (titleParagraph.Descendants(ns + "pStyle").First().Attribute(ns + "val").Value)
                {
                    case "Head1":
                        {
                            referenceTitleStyle = "TOC1";
                            tempheading = 1;
                            break;
                        }
                    case "Head2":
                        {
                            referenceTitleStyle = "TOC2";
                            tempheading = 2;
                            break;
                        }
                    case "Head3":
                        {
                            referenceTitleStyle = "TOC3";
                            tempheading = 3;
                            break;
                        }
                    case "Head4":
                        {
                            referenceTitleStyle = "TOC4";
                            tempheading = 4;
                            break;
                        }
                    case "Head5":
                        {
                            referenceTitleStyle = "TOC5";
                            tempheading = 5;
                            break;
                        }
                    case "Head6":
                        {
                            referenceTitleStyle = "TOC6";
                            tempheading = 6;
                            break;
                        }
                }


                string entryContent = "";
                IEnumerable<XElement> owTList = titleParagraph.Descendants(ns + "t");
                foreach (XElement entryElement in owTList)
                {
                    entryContent += (entryElement == null ? string.Empty : entryElement.Value);
                }

                XElement TOCElement = null;
                XElement tempTOCElement = TOCRefNode.Elements(ns + "sdtContent").First().Descendants().Where(
                tag =>
                    tag.Name == ns + "p" &&
                    tag.Descendants().Where
                    (
                        tag2 =>
                            tag2.Name == ns + "pStyle" &&
                            tag2.Attribute(ns + "val").Value == referenceTitleStyle
                    ).Count() > 0
                ).FirstOrDefault();

                if (tempTOCElement != null)
                {
                    if (maxHeading < tempheading)
                        maxHeading = tempheading;

                    TOCElement = new XElement(tempTOCElement);
                    //delete instrText which contains TOC 1-n
                    XElement instrTextTOC = TOCElement.Descendants().Where(
                            tag =>
                                tag.Name == ns + "r" &&
                                tag.Descendants().Where(
                                    tag2 =>
                                        tag2.Name == ns + "instrText" &&
                                        tag2.Value.Contains(@"TOC \o ")
                                ).Count() > 0

                        ).FirstOrDefault();
                    if (instrTextTOC != null)
                    {
                        instrTextTOC.ElementsAfterSelf(ns + "r").Remove();
                        instrTextTOC.ElementsBeforeSelf(ns + "r").Remove();
                        instrTextTOC.Remove();
                    }

                    //get hyperlink node
                    XElement hyperlink = TOCElement.Descendants().Where(
                            tag =>
                                tag.Name == ns + "hyperlink"

                        ).FirstOrDefault();
                    //update anchor attribute value
                    hyperlink.Attribute(ns + "anchor").Value = bookmarkName;

                    //get entry content node
                    XElement contentNode = hyperlink.Descendants().Where(
                            tag =>
                                tag.Name == ns + "r" &&
                                tag.Descendants().Where(
                                    tag2 =>
                                        tag2.Name == ns + "rStyle" &&
                                        tag2.Attribute(ns + "val").Value == "Hyperlink"
                                ).Count() > 0 &&
                                tag.Elements(ns + "t").Count() > 0

                        ).FirstOrDefault().Elements(ns + "t").FirstOrDefault();

                    contentNode.Value = entryContent;

                    //update PAGEREF value
                    XElement instrText = TOCElement.Descendants().Where(
                            tag =>
                                tag.Name == ns + "instrText" &&
                                tag.Value.Contains("PAGEREF ")
                        ).FirstOrDefault();
                    if (instrText != null)
                    {
                        instrText.Value = " PAGEREF " + bookmarkName + @" \h ";
                    }

                    sdtContent.Add(TOCElement);
                    bookMarkIdCounter++;
                }


            }

            sdtContent.Descendants().Where(
                tag =>
                    tag.Name == ns + "instrText" 
                    &&
                    tag.Value.Contains("TOCLIMIT")
                ).FirstOrDefault().Value = String.Format(@"TOC \o ""1-{0}"" \h \z \u ", maxHeading);

            sdtContent.Add(
                new XElement(ns + "p",
                    new XElement(ns + "r",
                        new XElement(ns + "fldChar",
                            new XAttribute(ns + "fldCharType", "end")))));

            //  Finish the xml construction of the TOC
            XElement TOC =
                new XElement(ns + "sdt",
                    new XElement(ns + "sdtPr",
                        new XElement(ns + "docPartObj",
                            new XElement(ns + "docPartGallery",
                                new XAttribute(ns + "val", "Table of Contents")),
                            new XElement(ns + "docPartUnique"))),
                    sdtContent);

            //  add it to the original document

            IEnumerable<XElement> tocNodes = xmlMainDocument.Descendants().Where
              (
                  tag =>
                      tag.Name == ns + "sdt" &&
                      tag.Descendants(ns + "sdtContent").Count() > 0 &&
                      tag.Descendants().Where
                      (
                        tag2 =>
                            tag2.Name == ns + "p" &&
                            tag2.Descendants().Where
                            (
                                tag3 =>
                                    tag3.Name == ns + "pStyle" &&
                                        (
                                            tag3.Attribute(ns + "val").Value == "TOCHeading"
                                        )
                            ).Count() > 0

                      ).Count() > 0
              );

            TOCRefNode.ReplaceWith(TOC);

        }


        #endregion
*/
    }
}
